package BeanUtils

import (
	"encoding/json"
	"fmt"
	"go/ast"
	"reflect"
	"strings"
	"time"
)

type (
	any     interface{}
	Handler func(source interface{}, dest interface{})
)

var StdOx = [...]string{time.Layout, time.ANSIC, time.UnixDate, time.RubyDate,
	time.RFC822, time.RFC822Z, time.RFC850, time.RFC1123, time.RFC1123Z,
	time.RFC3339, time.RFC3339Nano, time.Kitchen, time.Stamp, time.StampMilli,
	time.StampMicro, time.StampNano, time.DateTime, time.DateOnly, time.TimeOnly, "200601", "20060102", "2006-01", "01-02-06"}

// copyProperty copies fields from source to dist, handling nil values and nested structs
func copyProperty(source, dist any) {
	sourceVal, distVal := reflect.Indirect(reflect.ValueOf(source)), reflect.Indirect(reflect.ValueOf(dist))
	for i, sT := 0, sourceVal.Type(); i < sT.NumField(); i++ {
		sF := sT.Field(i)
		if !ast.IsExported(sF.Name) {
			continue
		}

		sourceField := sourceVal.Field(i)
		destField := distVal.FieldByName(sF.Name)

		switch {
		case sF.Anonymous && sF.Type.Kind() == reflect.Struct:
			copyProperty(sourceField.Interface(), dist)
		case sF.Type.Kind() == reflect.Slice:
			copySlice(sourceField, destField, sF.Type)
		default:
			copyField(sourceField, destField, sF.Type)
		}
	}
}

func copySlice(sourceField, destField reflect.Value, sliceType reflect.Type) {
	if sourceField.IsValid() && (!sourceField.IsNil() || !sourceField.IsZero()) {
		sliceEle := reflect.MakeSlice(sliceType, sourceField.Len(), sourceField.Len())
		for j := 0; j < sourceField.Len(); j++ {
			if sourceField.Index(j).Kind() == reflect.Ptr && !sourceField.Index(j).IsNil() {
				elem := reflect.New(sliceType.Elem()).Elem()
				CopyProperty(sourceField.Index(j).Interface(), elem.Addr().Interface())
				sliceEle.Index(j).Set(elem)
			} else {
				sliceEle.Index(j).Set(sourceField.Index(j))
			}
		}
		destField.Set(sliceEle)
	}
}

func copyField(sourceField, destField reflect.Value, fieldType reflect.Type) {
	if sourceField.IsValid() && (sourceField.Kind() != reflect.Ptr || !sourceField.IsNil()) {
		if destField.IsValid() && destField.CanSet() {
			if fieldType == destField.Type() {
				destField.Set(sourceField)
			} else {
				copySpecialTypes(sourceField, destField)
			}
		}
	}
}

func copySpecialTypes(sourceField, destField reflect.Value) {
	if sourceTime, ok := sourceField.Interface().(time.Time); ok {
		// Handle time.Time type conversion
		destField.SetString(sourceTime.Format(time.DateTime))
	}
}

func GetMonthBounds(date time.Time) (start, end time.Time) {
	// 获取月初
	start = time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, time.Local)
	// 获取月末
	end = start.AddDate(0, 1, 0).Add(-time.Second)
	return start.Local(), end.Local()
}

func GetYearStartAndEnd(year int) (time.Time, time.Time) {
	// 年初日期：1月1日
	yearStart := time.Date(year, time.January, 1, 0, 0, 0, 0, time.Local)

	// 年末日期：12月31日
	yearEnd := time.Date(year, time.December, 31, 23, 59, 59, 0, time.Local)

	return yearStart.Local(), yearEnd.Local()
}

// GetYearMonthRange 返回给定起始月和结束月之间的月份数组
func GetYearMonthRange(startMonth, endMonth time.Time) []string {
	var months []string

	// 从起始月份开始
	for current := startMonth; current.Before(endMonth) || current.Equal(endMonth); current = current.AddDate(0, 1, 0) {
		months = append(months, current.Format("2006-01"))
	}

	return months
}

func GetMonthRange(startMonth, endMonth time.Time) []int {
	var months []int

	// 从起始月份开始
	for current := startMonth; current.Before(endMonth) || current.Equal(endMonth); current = current.AddDate(0, 1, 0) {
		months = append(months, int(current.Month())) // 使用 int(current.Month()) 获取月份数字
	}

	return months
}

// GetLastMonthDate 获取上个月的年和月
func GetLastMonthDate(now time.Time) time.Time {
	return now.AddDate(0, -1, 0).Local() // 减去一个月
}

// GetLastYearSameMonthDate 获取去年的当月的年和月
func GetLastYearSameMonthDate(now time.Time) time.Time {
	lastYearSameMonth := now.AddDate(-1, 0, 0).Local() // 减去一年
	return lastYearSameMonth.Local()
}

// GetDateFormat 函数用于根据给定的日期格式解析字符串，并返回解析后的时间
func GetDateFormat(value string, errHandle ...func() time.Time) time.Time {
	//如果时间类型为空，默认为初始状态
	// 如果value为空，则返回空值
	if value == "" || value == "null" || len(value) == 0 || value == "0001-01-01 00:00:00" {
		value = "1893-01-01"
	}
	//为了处理2025/7/31这种格式的时间   将/替换成-
	if strings.Contains(value, "/") {
		value = strings.ReplaceAll(value, "/", "-")
	}
	// 遍历标准日期格式
	for _, format := range StdOx {
		// 使用给定的日期格式解析字符串
		date, err := time.Parse(format, strings.TrimSpace(value))
		// 如果解析失败，则继续下一个日期格式
		if err != nil {
			continue
		}
		/*// 打印解析后的日期
		fmt.Printf("dateformat: %s\n", date)*/
		// 返回解析后的时间
		return date.Local()
	}
	// 如果没有匹配的日期格式，则返回默认时间
	return func() time.Time {
		// 如果有错误处理函数，则返回错误处理函数返回的时间
		if len(errHandle) > 0 {
			return errHandle[0]()
		}
		// 否则返回默认时间
		return time.Time{}.Local()
	}()
}

func GetStartOfDay(ym string) time.Time {
	t := GetDateFormat(ym)
	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
}

// 获取一天的结束时间
func GetEndOfDay(ym string) time.Time {
	t := GetDateFormat(ym)
	return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, time.Local)
}

// 获取月初时间
func GetStartOfMonth(ym string) time.Time {
	t := GetDateFormat(ym)
	return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.Local)
}

// 获取月末时间
func GetEndOfMonth(ym string) time.Time {
	t := GetDateFormat(ym)
	// 下个月的月初减去1纳秒
	return time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, time.Local).Add(-time.Nanosecond).Local()
}

// 从日期中提取年、月、日
func GetYearMonthDay(date time.Time) string {
	// 获取年、月、日
	return fmt.Sprintf("%d-%s-%d", date.Year(), date.Month(), date.Day())
}

// 根据模板格式化时间
func FormatTime(t time.Time, format string) string {
	replacements := map[string]string{
		"YYYY": "2006", // 年
		"YY":   "06",   // 两位年
		"MM":   "01",   // 月
		"DD":   "02",   // 日
		"hh":   "15",   // 小时（24小时制）
		"mm":   "04",   // 分钟
		"ss":   "05",   // 秒
	}

	// 替换模板中的自定义格式为 Go 的时间格式
	for key, value := range replacements {
		format = strings.ReplaceAll(format, key, value)
	}

	return t.Format(format)
}

func getElementType(typ reflect.Type) reflect.Type {
	if typ.Kind() != reflect.Ptr {
		return typ
	}
	return typ.Elem()
}

func makeSlice(typ reflect.Type, length int) reflect.Value {
	if typ.Kind() != reflect.Ptr {
		return makeSliceByVal(typ, length)
	}
	return makeSliceByPtr(typ, length)
}

func makeSliceByPtr(typ reflect.Type, length int) reflect.Value {
	return reflect.MakeSlice(reflect.SliceOf(typ), length, length)
}

func makeSliceByVal(typ reflect.Type, length int) reflect.Value {
	return reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(typ)), length, length)
}

func getOriginalT(ele any) reflect.Value {
	return reflect.Indirect(reflect.ValueOf(ele))
}

func PrintTree(trees interface{}) {
	b, _ := json.MarshalIndent(trees, "", "    ")
	fmt.Println(string(b))
}

func ManualPagination[T any](data []T, page, limit int32) []T {
	// 检查页码和每页记录数是否有效
	if page < 1 || limit < 1 {
		return make([]T, 0)
	}
	// 计算起始索引和结束索引
	var start = int((page - 1) * limit)
	end := start + int(limit)
	// 如果起始索引超过数据长度，返回空切片
	if start >= len(data) {
		return make([]T, 0)
	}
	// 如果结束索引超过数据长度，则截断至数据末尾
	if end > len(data) {
		end = len(data)
	}
	// 返回分页后的数据
	return data[start:end]
}

// BoolToNumber 函数将 bool 转换为 1 或 0，并返回指定的数字类型
func BoolToNumber[T int32 | int | float64 | float32](b bool) T {
	if b {
		var result T
		return result + 1 // 对于 true，返回 1（相应的数字类型）
	}
	var result T
	return result // 对于 false，返回 0（相应的数字类型）
}
